#pragma once
#include<pthread.h>
#include<queue>
#include<iostream>
#include<string>
#include<cstring>
#include<unistd.h>
#include<sys/wait.h>
#include<sys/socket.h>
#include<arpa/inet.h>
#include<netinet/in.h>
#define NUM 5

class Task{
  private:
      int _sock; 
  public:
      Task(int sock)
        :_sock(sock)
      {
             
      }
      void run()
      {
           std::cout<<"run()"<<std::endl;
           char buffer[128];
           buffer[0] = 0;
           int ret = recv( _sock, buffer , sizeof(buffer)-1 , 0);
           if( ret < 0 )
           {
               std::cerr <<" recv error"<<std::endl;
               exit(4);
           }
           else if(ret == 0)/*对端关闭了*/
           {
               std::cerr<<" Client quit" <<std::endl;
           }
           else{
               buffer[ ret ] = 0;
               std::cout << buffer <<std::endl;
               std::string msg = "echo: ";
               msg += buffer;
               send(_sock , msg.c_str() , (int)msg.size(), 0);
           }
      }
      ~Task()
      {
          close(_sock);
      }
};

class pthreadPool{
    private:
      std::queue<Task*> _que;
      int _max_num;
      pthread_mutex_t lock;
      pthread_cond_t cond;
      void LockQueue()
      {
          pthread_mutex_lock(&lock); 
      }
      void UnlockQueue()
      {
          pthread_mutex_unlock(&lock);
      }
      bool IsEmpty()
      {
          return _que.size()==0;
      }
      void ThreadWait()
      {
          pthread_cond_wait(&cond,&lock);
      }

      void ThreadWakeUp()
      {
          pthread_cond_signal(&cond);
      }
    public:
      pthreadPool(int max_num = NUM)
      :_max_num(max_num)
      {}
      ~pthreadPool()
      {
         pthread_mutex_destroy(&lock);
         pthread_cond_destroy(&cond);
      }
      static void* Routine(void* arg)
      {
          pthreadPool *this_p = (pthreadPool*) arg;
          while(1)
          {
              this_p->LockQueue();
              while(this_p->IsEmpty())
              {
                  this_p->ThreadWait();
              }
              Task* t;
              this_p->Get(t);
              this_p->UnlockQueue();
              t->run();
              std::cout<<"task has run"<<std::endl;
              delete t;
          }
      }
      void pthreadPoolInit()
      {
          pthread_mutex_init(&lock,NULL);

          pthread_cond_init(&cond,NULL);

          std::cout<<"_max_num="<<_max_num<<std::endl; 
          pthread_t t;
          for(int i =0 ; i < _max_num ; i++)
          {
             pthread_create(&t,NULL,Routine,(void*)this);
             pthread_detach(t);
          }
      }

      void Put(Task* in)
      {
          LockQueue();
          _que.push(in);
          UnlockQueue();

          ThreadWakeUp();
          std::cout<<"task has put "<<std::endl;
      }
      void Get(Task* &out)
      {
          Task* t  = _que.front();
          _que.pop();
          out = t;
      }
};
